/*
 * INSANE - Interactive Structural Analysis Environment
 *
 * Copyright (C) 2003-2006
 * Universidade Federal de Minas Gerais
 * Escola de Engenharia
 * Departamento de Engenharia de Estruturas
 *
 * Author's email :     insane@dees.ufmg.br
 * Author's Website :   http://www.dees.ufmg.br/insane
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-
 * 1307, USA.
 * 
 */

package br.ufmg.dees.insane.util.extrapolation;

import java.util.ArrayList;

import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.INaturalCoords;
import br.ufmg.dees.insane.util.IPoint3d;

/** 
 * The class represents an lagrangean extrapolation.
 * @author Penna, Samuel & Pitangueira, Roque
 * @since novenber 2006
 */
public abstract class LagrangeanExtrapolation{
    
    /** The natural coords of all known points. */
    protected ArrayList naturalCoords;
    /** The known values to respective points. */
    protected ArrayList values;
	
	/**
	 * The default's constructor.
	 */
	public LagrangeanExtrapolation() {
    
    }
	
    /**
     * Initialize the lagrangean extrapolation to it values and it coords.
     */
	public LagrangeanExtrapolation(ArrayList natCoords,ArrayList values) {
	    this.naturalCoords = new ArrayList();
	    this.values = new ArrayList();
        this.naturalCoords = natCoords; 
        this.values = values;
    }
    
    /** 
     * The method return the qsi terms matrix of lagrangean's polynomial 
     * respective to it natural coords.
     * @param p The natural coords.
     * @return fiQsi The matrix with qsi terms.
     */
    protected IMatrix fiQsi(INaturalCoords p){
        int num = (int)Math.sqrt(this.naturalCoords.size());
        IMatrix fiQsi = new IMatrix(1,num);
        for(int i=0;i<num;i++){
            fiQsi.setElement(0,i,Math.pow(p.getCsi1(),i));
        }
        return fiQsi;
    }
    
    /** 
     * The method return the eta terms matrix of lagrangean's polynomial
     * respective to it natural coords.
     * @param p The natural coords.
     * @return fiEta The matrix with eta terms.
     */
    protected IMatrix fiEta(INaturalCoords p){
        int num = (int)Math.sqrt(this.naturalCoords.size());
        IMatrix fiEta = new IMatrix(1,num);
        for(int i=0;i<num;i++){
            fiEta.setElement(0,i,Math.pow(p.getCsi2(),i));
        }
        return fiEta;
    }
    
    /** 
     * The method return the zeta terms matrix of lagrangean's polynomial
     * respective to it natural coords.
     * @param p The natural coords.
     * @return fiZeta The matrix with zeta terms.
     */
    protected IMatrix fiZeta(INaturalCoords p){
        int num = (int)Math.sqrt(this.naturalCoords.size());
        IMatrix fiZeta = new IMatrix(1,num);
        for(int i=0;i<num;i++){
            fiZeta.setElement(0,i,Math.pow(p.getCsi3(),i));
        }
        return fiZeta;
    }
    
    /** 
     * The method return the terms of lagrangean's polynomial 
     * respective to it natural coords.
     */
    protected abstract IMatrix fi(INaturalCoords p);
    
    /**
     * The method compute the G matrix.
     * @return g The G matrix of 1D extrapolation.
     */
    public IMatrix mountG(){
        int num = this.naturalCoords.size();
        IMatrix g = new IMatrix(num,num); 
        int cont =0;
        for(int i=0;i<num;i++){
            for(int j=0;j<num;j++){
                g.setElement(i,j,fi((INaturalCoords)this.naturalCoords.get(cont)).getElement(0,j));
            }
            cont++;
        }
        return g;
    }
    
    /**
     * The method compute the inverse of G matrix.
     * @return invG The inverse of G matrix of 1D extrapolation;
     */
    public IMatrix invG(){
        IMatrix invG = this.mountG().pseudoInverse();
        return invG;
    }
    
    /**
     * The extrapolatede values of a point.
     * @param coords The coords of a the point 
     * @return value The extrapolated value.
     */
    public double extrapolateTo(IPoint3d p){
        INaturalCoords in = new INaturalCoords();
        in.csi1 = p.x;
        in.csi2 = p.y;
        in.csi3 = p.z;
        double value = 0.0;
        IMatrix fi = this.fi(in);
        IMatrix invG = this.invG(); 
        IMatrix values = this.valuesMatrix(); 
        IMatrix aux = invG; 
        aux.mul(values);
        fi.mul(aux);
        value = fi.getElement(0,0);
        return value;
    }
    
    /**
     * The method return the matrix of values.
     * @return valuesMatrix The Value matrix of this extrapolation.
     */
    public IMatrix valuesMatrix(){
        int num = this.values.size();
        IMatrix valuesMatrix =  new IMatrix(num,1);
        for (int i = 0; i < num; i++) {
            valuesMatrix.setElement(i,0,(Double)this.values.get(i));
        }
        return valuesMatrix;
    }
	
//*****************************************************************************
}//end of this class
